package com.atguigu.srb.core.service.impl;

import com.alibaba.excel.EasyExcel;
import com.atguigu.srb.core.listener.ExcelDictDTOListener;
import com.atguigu.srb.core.pojo.dto.ExcelDictDTO;
import com.atguigu.srb.core.pojo.entity.Dict;
import com.atguigu.srb.core.mapper.DictMapper;
import com.atguigu.srb.core.service.DictService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 数据字典 服务实现类
 * </p>
 *
 * @author DaYouZi
 * @since 2022-12-01
 */
@Slf4j
@Service
public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements DictService {


    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 上传excel，导入字典
     * @param inputStream
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void importData(InputStream inputStream) {
        // 这里 需要指定读用哪个class去读，然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(inputStream, ExcelDictDTO.class, new ExcelDictDTOListener(baseMapper)).sheet().doRead();
        log.info("importData finished");
    }

    /**
     * 下载excel，导出字典
     * @return
     */
    @Override
    public List<ExcelDictDTO> listDictData() {
        //从数据库获取字典数据
        List<Dict> dictList = baseMapper.selectList(null);

        //将dict转变成dto
        ArrayList<ExcelDictDTO> excelDictDTOArrayList = new ArrayList<>(dictList.size());
        dictList.forEach(dict -> {
            ExcelDictDTO excelDictDTO = new ExcelDictDTO();
            BeanUtils.copyProperties(dict, excelDictDTO);
            excelDictDTOArrayList.add(excelDictDTO);
        });

        return excelDictDTOArrayList;
    }

    /**
     * 展示字典列表
     * @param parentId
     * @return
     */
    @Override
    public List<Dict> listByParentId(Long parentId) {

        //先查询redis中是否存在数据
        List<Dict> dictList = null;
        try {
            dictList = (List<Dict>) redisTemplate.opsForValue().get("srb:core:dictList:" + parentId);
            if (dictList != null) {
                log.info("从redis中取值");
                return dictList;
            }
        } catch (Exception e) {
            log.error("redis服务器异常：" + ExceptionUtils.getStackTrace(e));
        }

        log.info("从数据库中取值");
        dictList = baseMapper.selectList(new QueryWrapper<Dict>().eq("parent_id", parentId));
        dictList.forEach(dict -> {
            //判断是否有子节点
            boolean hasChildren = this.hasChildren(dict.getId());
            dict.setHasChildren(hasChildren);
        });

        //将数据存入redis
        try {
            redisTemplate.opsForValue().set("srb:core:dictList:" + parentId, dictList, 5, TimeUnit.MINUTES);
            log.info("数据存入redis");
        } catch (Exception e) {
            log.error("redis服务器异常：" + ExceptionUtils.getStackTrace(e));
        }

        return dictList;
    }

    /**
     * 判断是否有子节点
     * @param id
     * @return
     */
    private boolean hasChildren(Long id) {
        Integer count = baseMapper.selectCount(new QueryWrapper<Dict>().eq("parent_id", id));
        if (count > 0) {
            return true;
        }
        return false;
    }

    @Override
    public List<Dict> findByDictCode(String dictCode) {
        //先根据dictCode查出对应id，再根据上面的方法，根据父id获取子列表
        return listByParentId(baseMapper.selectOne(new QueryWrapper<Dict>().eq("dict_code", dictCode)).getId());
    }

    /**
     * 通过字典编码以及值，获取对应字典名称
     * @param dictCode
     * @param value
     * @return
     */
    @Override
    public String getNameByParentDictCodeAndValue(String dictCode, Integer value) {
        //先使用编码查询父类
        Dict parentDict = baseMapper.selectOne(new QueryWrapper<Dict>().eq("dict_code", dictCode));
        if (parentDict == null) {
            return "";
        }

        //再根据父id及value，查出具体字典名称
        Dict dict = baseMapper.selectOne(new QueryWrapper<Dict>()
                .eq("parent_id", parentDict.getId())
                .eq("value", value));
        if (dict == null) {
            return "";
        }
        return dict.getName();
    }
}
